package com.jungle.sp.daily.service;

import jakarta.annotation.PostConstruct;
import jakarta.annotation.Resource;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Service;
import org.springframework.util.StopWatch;

import java.util.Optional;
import java.util.Random;
import java.util.Set;

/**
 * @author 86189
 */
@Service
public class RaffleService {

    @Resource
    private RedisTemplate<String, Object> redisTemplate;

    private static final String RAFFLE_POOL_KEY = "raffle_pool:";

    @PostConstruct
    public void initializeRafflePoolWithWeights() {
        redisTemplate.delete(RAFFLE_POOL_KEY); // 清空现有数据

        // 添加数据，支持小数权重
        addUserToRafflePool(101L, 80);  // 权重 10.5
        addUserToRafflePool(102L, 0);     // 权重 0，不会被抽中
        addUserToRafflePool(103L, 8);  // 权重 20.2
        addUserToRafflePool(104L, 10);     // 权重 5
    }

    // 向 Redis Sorted Set 中添加用户及其权重
    public void addUserToRafflePool(Long userId, double weight) {
        ZSetOperations<String, Object> zSetOps = redisTemplate.opsForZSet();
        zSetOps.add(RAFFLE_POOL_KEY, userId, weight); // 权重作为分数
    }

    // 按照权重随机抽取一个用户，不删除用户
    public Object drawRandomRaffleWithWeight() {
        // 获取所有元素及其权重
        Set<ZSetOperations.TypedTuple<Object>> range = redisTemplate.opsForZSet().rangeWithScores(RAFFLE_POOL_KEY, 0, -1);

        if (range == null || range.isEmpty()) {
            return null; // 抽奖池为空
        }

        // 使用 Stream 计算总权重，确保 getScore 不为 null
        double totalWeight = range.stream()
                .mapToDouble(tuple -> Optional.ofNullable(tuple.getScore()).orElse(0.0)) // 默认权重为 0
                .filter(score -> score > 0) // 忽略权重为 0 的元素
                .sum();

        if (totalWeight == 0) {
            return null; // 全部权重为 0
        }

        // 随机生成一个权重值
        double randomValue = new Random().nextDouble() * totalWeight;

        // 使用 Stream 根据累计权重随机抽取
        final double[] cumulativeWeight = {0};
        return range.stream()
                .filter(tuple -> Optional.ofNullable(tuple.getScore()).orElse(0.0) > 0) // 忽略权重为 0 的元素
                .peek(tuple -> cumulativeWeight[0] += Optional.ofNullable(tuple.getScore()).orElse(0.0)) // 累加权重
                .filter(tuple -> cumulativeWeight[0] >= randomValue)   // 找到随机值所在区间
                .map(ZSetOperations.TypedTuple::getValue)             // 获取用户 ID
                .findFirst()
                .orElse(null); // 返回用户 ID，未找到返回 null
    }

    // 示例调用
    public void raffle() {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        initializeRafflePoolWithWeights();
        int sum = 0;

        // 随机抽取 5 次
        for (int i = 0; i < 1000000; i++) {
            Long winner = (Long) drawRandomRaffleWithWeight();
            if (winner == 102) {
                sum++;
            }

        }
        stopWatch.stop();
        // System.out.println(STR."总耗时: \{stopWatch.getTotalTimeSeconds()}");
        // System.out.println(STR."102出现的总次数: \{sum}");

    }
}
